package org.intelligentsia.keystone.mygod;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 
 * @author <a href="mailto:jguibert@intelligents-ia.com" >Jerome Guibert</a>
 */
public class BootClassLoader extends URLClassLoader {

	public BootClassLoader(final URL[] urls, final ClassLoader parent) {
		super(urls, parent);
		try {
			final ProtectionDomain protectionDomain = getClass().getProtectionDomain();
			final CodeSource codeSource = protectionDomain.getCodeSource();
			final URL rootJarUrl = codeSource.getLocation();
			final String rootJarName = rootJarUrl.getFile();
			if (BootClassLoader.isJar(rootJarName)) {
				addJarResource(new File(rootJarUrl.getPath()));
			}
		} catch (final IOException e) {
			// e.printStackTrace();
		}
	}

	private static boolean isJar(final String fileName) {
		return (fileName != null) && fileName.toLowerCase().endsWith(".jar");
	}

	private void addJarResource(final File file) throws IOException {
		System.err.println("Adding " + file.getName());
		final JarFile jarFile = new JarFile(file);
		addURL(file.toURI().toURL());
		final Enumeration<JarEntry> jarEntries = jarFile.entries();
		while (jarEntries.hasMoreElements()) {
			final JarEntry jarEntry = jarEntries.nextElement();
			if (!jarEntry.isDirectory() && BootClassLoader.isJar(jarEntry.getName())) {

				System.err.println("addJarResource " + jarEntry.getName());
				addJarResource(BootClassLoader.jarEntryAsFile(jarFile, jarEntry));
			}
		}
	}

	private static File jarEntryAsFile(final JarFile jarFile, final JarEntry jarEntry) throws IOException {
		InputStream input = null;
		OutputStream output = null;
		try {
			final String name = jarEntry.getName().replace('/', '_');
			final int i = name.lastIndexOf(".");
			final String extension = i > -1 ? name.substring(i) : "";
			final File file = File.createTempFile(name.substring(0, name.length() - extension.length()) + ".",
					extension);
			file.deleteOnExit();
			input = jarFile.getInputStream(jarEntry);
			output = new FileOutputStream(file);
			int readCount;
			final byte[] buffer = new byte[4096];
			while ((readCount = input.read(buffer)) != -1) {
				output.write(buffer, 0, readCount);
			}
			return file;
		} finally {
			BootClassLoader.close(input);
			BootClassLoader.close(output);
		}
	}

	private static void close(final Closeable closeable) {
		if (closeable != null) {
			try {
				closeable.close();
			} catch (final IOException e) {
				// e.printStackTrace();
			}
		}
	}

	@Override
	protected synchronized Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
		try {
			Class<?> clazz = findLoadedClass(name);
			if (clazz == null) {
				clazz = findClass(name);
				if (resolve) {
					resolveClass(clazz);
				}
			}
			return clazz;
		} catch (final ClassNotFoundException e) {
			return super.loadClass(name, resolve);
		}
	}
}
